﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using Roborally.CommonData.Enums;
using Roborally.CommonData.GlobaleTypes;
using Roborally.Netwerklaag;

namespace Roborally.Protocollaag
{
    public class Protocollaag
    {
        public NetwerkLaag netwerkconnectie;
        public delegate void Nieuwespeler(object sender, NieuweSpelerArgs Nieuwespeler);
        public delegate void OntvangBericht(object sender, VertaaldBinnenkomendBericht vertaaldbinnenkomendbericht);
        public delegate void DisconnectClient(object sender, DisconnectClientX client);
        public delegate void JoinKamer(object sender, JoinKamerClientX client);
        public event Nieuwespeler nieuwespeler;
        public event OntvangBericht ontvangbericht;
        public event DisconnectClient disconnectclient;
        public event JoinKamer joinkamer;

        public Protocollaag()
        {
            netwerkconnectie = new NetwerkLaag();
        }

        public void StartServer()
        {
            netwerkconnectie.nieuwespeler += new NetwerkLaag.Nieuwespeler(NetwerkNieuweSpeler);
            netwerkconnectie.ontvangbericht += new NetwerkLaag.OntvangBericht(NetwerkOntvangBericht);
            netwerkconnectie.disconnectclient += new NetwerkLaag.DisconnectClient(NetwerkDisconnectClient);
            netwerkconnectie.joinkamer += new NetwerkLaag.JoinKamer(NetwerkJoinKamer);
            netwerkconnectie.Start_Server();
        }

        private void NetwerkJoinKamer(object sender, JoinKamerClientX client)
        {
            if(joinkamer != null)
            {
                joinkamer(sender, client);
            }
        }

        public bool StuurBericht(BerichtType type, string data, TcpClient client)
        {
            List<TcpClient> clients = new List<TcpClient>();
            clients.Add(client);
            return StuurBericht(type, data, clients);
        }

        public bool StuurBericht(BerichtType type, string data, List<TcpClient> clients)
        {
            if (data.Length > 0)
            {
                string prefix = "";

                switch (type)
                {
                    case BerichtType.AndereSpelerJointKamer:
                        prefix = "*SERVER* AndereSpelerJointKamer:";
                        break;
                    case BerichtType.AndereSpelerLeavedKamer:
                        prefix = "*SERVER* AndereSpelerLeavedKamer:";
                        break;
                    case BerichtType.ChatBericht:
                        prefix = "*SERVER* ChatBericht:";
                        break;
                    case BerichtType.DeelKaarten:
                        prefix = "*SERVER* DeelKaarten:";
                        break;
                    case BerichtType.JoinKamer:
                        prefix = "*SERVER* JoinKamer:";
                        break;
                    case BerichtType.NaamGoedkeuring:
                        prefix = "*SERVER* NaamGoedkeuring:";
                        break;
                    case BerichtType.SpelBegint:
                        prefix = "*SERVER* SpelBegint:";
                        break;
                    case BerichtType.SpelerReady:
                        prefix = "*SERVER* SpelerReady:";
                        break;
                    case BerichtType.TekenBord:
                        prefix = "*SERVER* TekenBord:";
                        break;
                    case BerichtType.UpdateSpelers:
                        prefix = "*SERVER* UpdateSpelers:";
                        break;
                    case BerichtType.VraagKamerLijst:
                        prefix = "*SERVER* VraagKamerLijst:";
                        break;
                }

                if (prefix != "")
                {
                    int fails = 0;
                    for (int i = 0; i < clients.Count; i++)
                    {
                        if (!netwerkconnectie.Stuur_Bericht(prefix + data, clients[i]))
                        {
                            fails++;
                            Console.WriteLine("Unable to send: " + prefix + data + " to: " + clients[i].ToString());
                            disconnectclient(this, new DisconnectClientX(clients[i]));
                        }
                    }
                    if (fails < clients.Count)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    Console.WriteLine("Onbekende actie: " + type.ToString());
                    return false;
                }
            }
            return false;
        }

        private void NetwerkDisconnectClient(object sender, DisconnectClientX Disconnectclient)
        {
            disconnectclient(this, Disconnectclient);
        }

        private void NetwerkOntvangBericht(object sender, BinnenkomendBericht Binnenkomendbericht)
        {
            try
            {
                string bericht = Binnenkomendbericht.Bericht();
                BerichtType berichttype = new BerichtType();
                Boolean goedbericht = true;
                if (bericht.Substring(0, "*CLIENT* ".Length) == "*CLIENT* ")
                {
                    bericht = bericht.Substring("*CLIENT* ".Length);
                    string[] data = bericht.Split(':');
                    if (data.Count() > 2)
                    {
                        string[] temp = { "", "" };
                        temp[0] = data[0];
                        temp[1] = data[1];
                        for (int i = 2; i < data.Count(); i++)
                        {
                            temp[1] += ":" + data[i];
                        }
                        data = temp;
                    }
                    switch (data[0])
                    {
                        case "ChatBericht":
                            berichttype = BerichtType.ChatBericht;
                            break;
                        //case "Connect":
                            //berichttype = BerichtType.Connect;
                            //mag/zal nooit gebeuren aangezien dit anders afgehandelt wordt
                            //break;
                        case "Disconnect":
                            berichttype = BerichtType.Disconnect;
                            break;
                        case "JoinKamer":
                            berichttype = BerichtType.JoinKamer;
                            break;
                        case "LeaveKamer":
                            berichttype = BerichtType.LeaveKamer;
                            break;
                        case "MaakKamer":
                            berichttype = BerichtType.MaakKamer;
                            break;
                        case "NieuweNaam":
                            berichttype = BerichtType.NieuweNaam;
                            break;
                        case "Spelstarten":
                            berichttype = BerichtType.SpelStarten;
                            break;
                        case "SpelerReady":
                            berichttype = BerichtType.SpelerReady;
                            break;
                        case "VraagKamerLijst":
                            berichttype = BerichtType.VraagKamerLijst;
                            break;
                        case "ClientData":
                            berichttype = BerichtType.ClientData;
                            break;
                        default:
                            goedbericht = false;
                            break;
                    }
                    if (goedbericht)
                    {
                        if (data.Length > 0)
                            ontvangbericht(this, new VertaaldBinnenkomendBericht(berichttype, data[1], Binnenkomendbericht.TcpClient()));
                    }
                    else
                    {
                        Console.WriteLine("Kon bericht type niet vast stellen:" + Binnenkomendbericht.Bericht());
                    }
                }
            }
            catch (Exception ex) { Console.WriteLine("Exception gevangen: " + ex.ToString()); };
        }

        /// <summary>
        /// gebeurt als er een nieuwe speler connect
        /// </summary>
        private void NetwerkNieuweSpeler(object sender, NieuweSpelerArgs de_args)
        {
            if (nieuwespeler != null)
            {
                if (de_args.Naam().Substring(0, "*CLIENT* connect:".Length) == "*CLIENT* connect:")
                {
                    string naam = de_args.Naam().Substring("*CLIENT* connect:".Length);

                    nieuwespeler(sender, new NieuweSpelerArgs(naam, de_args.TcpClient()));
                }
            }
        }
    }
}
